package Controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPListParseEngine;

/**
 * Esta es la clase principal de nuestro cliente de FTP. Va a ser la clase que
 * descifre los mensajes del usuario y genere los hilos para subir o bajar los
 * archivos.
 *
 * @author Sleepy & Nexo
 */
public class ClientFTP {

    static FTPClient client;
    static File localDir;
    //static FTPFile remoteDir;
    static String remotePathStart = ".\\";

    public ClientFTP() {
        client = new FTPClient();
        localDir = new File(".");
        localDir = new File(localDir.getAbsolutePath().toString());
        localGoUp();
    }

    public String getLocalDirString() {
        return localDir.getAbsolutePath();
    }

    public void localGoUp() {
//        System.out.println("Directorio actual: " + localDir.toString());
//        System.out.println("El directorio al que queremos subir: " + localDir.getParentFile());
        localDir = localDir.getParentFile();
    }

    public void localGoInto(String newDir) {
//        System.out.println(localDir.getAbsolutePath() + newDir);
//        System.out.println("El viejo direcotrio es: " + localDir.getAbsoluteFile());
        //localDir = new File(localDir.getAbsoluteFile() + newDir);
        localDir = new File(localDir.getAbsolutePath(), newDir);
//        System.out.println("El nuevo direcotrio es: " + localDir.getAbsoluteFile());
    }

    public void remoteGoInto(String newDir) {
        try {
            client.changeWorkingDirectory(newDir);
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public String getRemoteDirString() {
        try {
            return client.printWorkingDirectory();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public void remoteGoUp() {
        try {
            client.changeToParentDirectory();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public File getLocalDir() {
        return localDir;
    }

    public void setLocalDir(File newDir) {
        localDir = newDir;
    }

//    public FTPFile getRemoteFile(){
//        return remoteDir;
//    }
    public String getWorkingDir() {
        try {
            return client.printWorkingDirectory();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public String[] printChildren() {
        try {
            return client.listNames();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public FTPFile[] getChildren(String dir) {
        try {
            FTPListParseEngine engine = client.initiateListParsing(dir);
            FTPFile[] files = engine.getFiles();
            return files;
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public void changeLocalDir(String path) {
        localDir = new File(localDir.getAbsoluteFile() + path);
    }

    public void changeRemoteDir(String path) {
        try {
            if (path.equals("..")) {
                client.changeToParentDirectory();
            } else {
                client.changeWorkingDirectory(path);
            }
        } catch (IOException ex) {
            Controller.print("No se ha podido cambiar de directorio.");
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void createRemoteDir(String dir) {
        try {
            client.makeDirectory(dir);
            showReply();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void removeRemoteDir(String dir) {
        try {
            client.removeDirectory(dir);
            showReply();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void showReply() {
        Controller.print(client.getReplyString());
    }

    public void connect(String host, int port) {
        try {
            checkConnected();
            client.connect(host, port);
            showReply();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void login(String user, String pass) {
        try {
            client.login(user, pass);
            showReply();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void logout() {
        try {
            client.logout();
            showReply();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void disconnect() {
        try {
            client.disconnect();
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void deleteRemoteFile(String file) {
        try {
            client.deleteFile(file);
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void createRemoteFile(String file) {

    }

    public void showLocalFilesHere() {
        ArrayList<File> dirList = new ArrayList();
        ArrayList<File> fileList = new ArrayList();
        System.out.println("Showing local files at " + localDir.getAbsolutePath());
        for (File file : localDir.listFiles()) {
            if (file.isFile()) {
                fileList.add(file);
            } else {
                dirList.add(file);
            }
        }
        for (File dir : dirList) {
            //System.out.printf("├ " + dir.getName() + "\t\t\t" + "D \n");
            System.out.printf("├ %-20s %10s" + " D \n", dir.getName(), " ");
        }
        for (File file : fileList) {
            System.out.printf("├ %-20s %10s" + " bytes \n", file.getName(), file.length());
            //System.out.print("├─ " + _file.getName() + "\t\t\t" + " " + _file.length() + " bytes \n");
        }
    }

    public void showRemoteFilesHere() {
        showRemoteFiles(".");
    }

    public void showRemoteFiles(String directory) {
        try {
            FTPListParseEngine engine = client.initiateListParsing(directory);
            FTPFile[] files = engine.getFiles();
            System.out.println("\nShowing files in: " + client.printWorkingDirectory() + directory);
            for (FTPFile file : files) {
                System.out.println(file.toString());
            }
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    //Esto se ejecutará en Thread en el futuro
    public void download(String remoteFilePath, String localFilePath) {
        try {
            FileOutputStream fos = new FileOutputStream(localDir.getAbsolutePath() + "\\" + localFilePath);
            showReply();
            client.retrieveFile(remoteFilePath, fos);
            fos.close();
            Controller.print("Archivo descargado satisfactoriamente");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void upload(ArrayList<String> files) {
        while (!files.isEmpty()) {
            upload(files.get(0), files.get(0));
            files.remove(0);
        }
    }

    //Esto se ejecutará en Thread en el futuro
    //Despues de los uploads hay que volver al modo activo
    public void upload2(String fileOrigin, String fileDestiny) {
        try {
            System.out.println("joojo");
            client.enterLocalPassiveMode();
            client.setFileType(FTPClient.BINARY_FILE_TYPE);
            File origen = new File(localDir.getAbsolutePath() + "\\" + fileOrigin);
            FileInputStream fis = new FileInputStream(origen);
            //Aqui el destino es local
            System.out.println(client.storeFile(localDir.getAbsolutePath() + fileDestiny, fis));
            showReply();
            fis.close();
//            boolean b = client.completePendingCommand();
//            System.out.println(b);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void upload(String fileName, String localFileFullName) {
        try {
            client.enterLocalPassiveMode();
            client.setFileType(FTPClient.BINARY_FILE_TYPE);
            InputStream is = new FileInputStream(new File(localFileFullName));
            client.storeFile(fileName, is);
            showReply();
            is.close();
        }   catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public boolean isConnected() {
        return client.isConnected();
    }

    public void checkConnected() {
        try {
            if (client.isConnected()) {
                client.logout();
                client.disconnect();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public boolean changeDir(String dir) {
        try {
            return client.changeWorkingDirectory(dir);
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }

    public void prepToUpload() {
        try {
            client.enterLocalPassiveMode();
            client.setFileType(FTPClient.BINARY_FILE_TYPE);
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void createLocalDir(String newDir) {
        File theDir = new File(newDir);
        if (!theDir.exists()) {
            theDir.mkdir();
            Controller.print("Archivo creado satisfactoriamente.");
        }
    }

    public void renameLocalDir(String oldDir, String newDir) {
        File file = new File(oldDir);
        File file2 = new File(newDir);
        if (file2.exists()) {
            try {
                throw new java.io.IOException("No puede ser renombrado: el archivo ya existe.");
            } catch (IOException ex) {
                Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        boolean success = file.renameTo(file2);
        if (!success) {
            Controller.print("Archivo no renombrado.");
        } else {
            Controller.print("Archivo renombrado satisfactoriamente.");
        }
    }

    public void renameRemoteDir(String oldName, String newName) {
        try {
            client.rename(oldName, newName);
            Controller.print("Archivo renombrado satisfactoriamente.");
        } catch (IOException ex) {
            Logger.getLogger(ClientFTP.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void deleteLocalFile(String target) {
        try {
            File file = new File(target);
            if (file.delete()) {
                Controller.print("Archivo borrado satisfactoriamente");
            } else {
                Controller.print("No se ha podido borrar el archivo");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
